MSDN:
The BitBlt function performs a bit-block transfer of the color data corresponding to a rectangle of pixels from the specified source device context into a destination device context.
Plain English:
BitBlt allows you to overlay color, or an image, over a device. That device could be a button, static box, or another image.
What you get when you are done:
When you are done you will know how to initialize a DC, load a bitmap into a DC and a HBITMAP, manually create a static box, a basic understanding of how BitBlt works and its different parameters, and finally how to clean up the memory you have used after you are done BitBlt'ng.
What we are going do:
We are going to BitBlt a bitmap to a static box on a window.
Insight:
BitBlt was, and sometimes still is, one function that will drive me to creating new swear words to yell at my computer. Unlike most other functions that will do something tangible even if it failed to do what you thought it would, BitBlt wont. If you have an incorrect parameter or your DCs are incorrect, lots of times nothing will happen on the screen. When this happens, get ready for the fun of hunting down the problem.
Headers Needed:
The standard Windows header, windows.h, has all the functions we will need.
Before We Start:
'This tutorial is only going to cover the basics of BitBlt. I am going to assume that you already know the basics of building a window, windows messages, and HWNDs. If you don't you might want to go do those tutorials first, because I am going to just assume you know how to do these things.
Also, before we start, you are going to need a bmp file to work with. I suggest you find, or create, a simple bitmap, maybe 50x50 pixel. Also, to make your life a whole lot easier, I might suggest that when we make the static box to BitBlt to, you make it the exact same size as your bitmap. Once you make (You can use Paint or VC++ Bitmap Editor), or find a bitmap you want to use, load it into the resource file as IDB_ OURBITMAP.
Show Stoppers:
One thing that is really important to know before we get to far into this is that, when something is BitBlt'ed to something else, it is really not there. An example is, with this tutorial you will be BitBlt'ng a bitmap to a static box. Since it is not really on the static box, whenever the window is refreshed, or needs to be refreshed (Example the tool tip on the "Close Window" X, will make a part of the image disappear), the bitmap will disappear. The problem is that here in the Basic BitBlt I am not going to teach you how to fix this problem. So your are going to have to be careful not to refresh the image (Such as minimizing it, or moving another window in front of it. Oh and just so you know a debugging break will do it). Also you are going to have to ensure that you do not have any code that is making the window refreshing after the BitBlt function is run.
Big Words:
1. DC (Device Context): Structure that defines a set of graphic objects and their attributes, and the graphic modes that affect output. In addition, the device context (DC) refers to a physical output device-its name, device driver, and other attributes. GDI function call parameters contain a handle to a DC to include the attributes of the specified device. There are four types of DC: display (supports drawing operations on a video display terminal), printer (supports drawing operations on a printer or plotter), memory (supports drawing operations on a bitmap), and information (supports retrieval of device data.)
2. Handle: A variable that identifies an object; an indirect reference to an operating system resource.
3. HDC (Handle to Device Context): A handle to a DC
4. HBITMAP: A handle to a bitmap
Get To Work:
I am going to make a .h and .cpp file called bitbltgraphics
[CODE]
/********************************************************************** *****
Name: bitbltgraphics.h
Version: 1.0
Date Created: 3/29/2001
Discription: This is the header file for bitbltgraphics.cpp
Notes: Created for BitBlt tutorial
Owner: Technocrat(technocrat@usa.com)
********************************************************************** *****/
#ifndef __BITBLTGRAPHICS_H__
#define __BITBLTGRAPHICS_H__
/*---------------------------------*/
//Header Files
#include "main.h" //You should always include the header file for your main file
#include <windows.h>
//I am including
this just incase, for some unknown reason, you don't have it in your main header
file
//If you do have this in the main header file delete it.
/*---------------------------------*/
//Declarations
bool LoadGraphics(HINSTANCE hInst); //We will use this function to load all bitmap, set the DCs, etc
bool DrawGraphics(HDC *hdc,int destX, int destY, int destWidth,int destHeight); //We will use this function to actually BitBlt
void CleanUp(); //We will use this function to do memory cleanup when we are done
/*---------------------------------*/
//Global VARs
extern
HBITMAP h_OurBitmap;
//This is the handle that will be for our bitmap.
//Normally I would name it something like m_hBitmap_WindowBack, but to keep
it simple I named it this
extern
HDC
hdc_OurBitmap;
//This is the HDC that will
be for our bitmap.
//Normally I would name it something like m_hDC_WindowBack, but to keep it simple
I named it this
/*---------------------------------*/
#endif //BITBLTGRAPHICS_H
[/CODE]
Here is the whole code. I will explain each piece after this.
[CODE]
/********************************************************************** *****
Name: bitbltgraphics.cpp
Version: 1.0
Date Created: 3/29/2001
Discription:
This
will provide all of the graphic functions
Loading graphics into HBITMAPs and DCs
BitBlting graphics to a DC
Cleaning up memory
Notes: Created for BitBlt tutorial
Owner: Technocrat(technocrat@usa.com)
********************************************************************** *****/
/*---------------------------------*/
//Headers
#include "bitbltgraphics.h"
/*---------------------------------*/
//Global
VARs
HBITMAP
h_OurBitmap;
//This
is the handle that will be for our bitmap.
//Normally I would name it something
like m_hBitmap_WindowBack, but to keep it simple I named it this
HDC
hdc_OurBitmap;
//This is the HDC that will be for our bitmap.
//Normally
I would name it something like m_hDC_WindowBack, but to keep it simple I named
it this
/*---------------------------------*/
/*############################################################## #############################*/
bool LoadGraphics(HINSTANCE hInst)
{
//Init the DC
hdc_OurBitmap
= CreateCompatibleDC(NULL);
//Load the bitmap into the HBITMAP and HDC
h_OurBitmap
= (HBITMAP)SelectObject(hdc_OurBitmap,LoadBitmap(hInst,MAKEINTRESOURCE(IDB_OURBITMAP))
);
//Insure that both loaded correctly
if((h_OurBitmap
== NULL) || (hdc_OurBitmap == NULL))
{
MessageBox(NULL,"Either your DC or HBITMAP, did not load correctly",NULL,NULL);
return false; //If they did not return
false
}
else
return true; //If they did return
true
}
/*############################################################## #############################*/
bool DrawGraphics(HDC *hdc, int destX, int
destY, int destWidth, int destHeight)
{
//Here is where all of the hard work is put to work
BitBlt
(*hdc,destX,destY,destWidth,destHeight,hdc_OurBitmap,0,0,SRCCOPY);
return true;
}
/*############################################################## #############################*/
void CleanUp()
{
//Cleans up the memory by destroying our the DC and the
HBITMAP
DeleteDC(hdc_OurBitmap);
DeleteObject(h_OurBitmap);
}
[/CODE]
Ok now that we have the header file done, we can now get down to some actual work.
Well let's get started, here is the top of the bitlbtgraphics.cpp file
[CODE]
/********************************************************************** *****
Name: bitbltgraphics.cpp
Version: 1.0
Date Created: 3/29/2001
Discription:
This
will provide all of the graphic functions
Loading graphics into HBITMAPs and DCs
BitBlting graphics to a DC
Cleaning up memory
Notes: Created for BitBlt tutorial
Owner: Technocrat(technocrat@usa.com)
********************************************************************** *****/
/*---------------------------------*/
//Headers
#include "bitbltgraphics.h"
/*---------------------------------*/
//Global
VARs
HBITMAP
h_OurBitmap;
//This
is the handle that will be for our bitmap.
//Normally I would name it something like m_hBitmap_WindowBack, but to keep
it simple I named it this
HDC
hdc_OurBitmap;
//This is the
HDC that will be for our bitmap.
//Normally I would name it something like m_hDC_WindowBack, but to keep it simple
I named it this
/*---------------------------------*/
[/CODE]
Nothing really exciting here. Just the .cpp info, the include statement, and the global variables. You should have no problem with any of these. If you do, then the next part is going to get you really lost, and you might want to go to a more basic tutorial.
Ok now we are going have to initialize our DC and then put our bitmap into the DC and handle to the bitmap. We will do this in the LoadGraphics function.
In order for us to do this we will need to have the instance of our program. So when we call this function we will pass it in. When we get to the main.cpp you will see how we pass it in. For right now just pretend that it is there and being passed in at the call of the function.
Ok so lets look at our function:
bool LoadGraphics(HINSTANCE hInst)
As you can see we are passing in the instance. We will return a true or false, depending on if both the DC and HBITMAP have the bitmap loaded into them.
The first thing we are going to need to do is initialize our DC. We do this with:
hdc_OurBitmap = CreateCompatibleDC(NULL);
What we are doing is setting hdc_OurBitmap equal to a compatible DC. Since of course we do not have a DC we want this to be compatible with (We are just initializing it remember) we are telling it to create a NULL, DC. That's it, we have just initialized our DC, now we have to put our bitmap into it.
We are going to do this and load it into the handle for the bitmap at the same time. We do this with:
h_OurBitmap = (HBITMAP)SelectObject(hdc_OurBitmap,LoadBitmap(hInst,MAKEINTRESOURCE(IDB_OURBITMAP)) );
Ok so, lets break this down. First :
LoadBitmap(hInst,MAKEINTRESOURCE(IDB_OURBITMAP))
We are loading a bitmap as you can see.
The first parameter is the instance that we want to load the bitmap from.
As I stated above we are passing into the function the handle of the instance
(HINSTANCE) of the program, in a variable called hInst. As you can see
that's what we are going to use for the instance parameter.
The second parameter is a sting that points to the bitmap we are going to use.
MAKEINTRESOURCE is a predefine macro that, VC++ provides, to turn a integer
(Which is what the IDB_OURBITMAP actually points too. Don't forget that
IDB_OURBITMAP is what we called our bitmap when we loaded it into the resource
file) into string that points to our bitmap.
In the future if you have a bitmap that is not in your resource file you can
take out MAKEINTRESOURCE and put in a string that points to your file.
An example would be "C:\\My Documents\\Images\\OurBitmap.bmp". Don't
forget to use the double \ to state you are actually using a \ and not a string
format command.
Bah, that was a lot and that was just ½ of that line of code. Now to actually load it into the DC and HBITMAP. Ok, so now lets look at it:
h_OurBitmap = (HBITMAP)SelectObject(hdc_OurBitmap,LoadBitmap...
First lets cover SelectObject. SelectObject function puts a device into a DC. So with that in mind, the first parameter is the DC you want to put the device into. In this case, it's the DC we setup to hold the bitmap. The second parameter is the device you want to put into the DC. In this case it's our bitmap, which will come from LoadBitmap.
Ok now all that's left is h_OurBitmap = (HBITMAP)SelectObject...
We are telling our HBITMAP variable, h_ourBitmap, to be equal to (HBITMAP)?? Well what were actually doing is telling VC++ to convert everything to the right of (HBITMAP) to a HBITMAP. So after it gets done loading our bitmap, putting it in the DC, to convert it to an HBITMAP and then set h_ourBitmap equal to it. That's it, we have loaded our bitmap.
A quick look at the order in which this line runs
1) Convert IDB_OURBITMAP in to a string
2) Load the bitmap that is pointed to by the string in 1, in the instance that set in the first parameter of the LoadBitmap function
3) Load that bitmap device into the DC, hdc_OurBitmap
4) Convert that DC into a HBITMAP
5) Set h_ourBitmap equal to that newly converted HBITMAP
Ok now we are going to do some error checking, to be sure that the bitmap loaded correctly.
if((h_OurBitmap == NULL) || (hdc_OurBitmap == NULL))
{
MessageBox(NULL,"Either your DC or HBITMAP, did not load correctly",NULL,NULL);
return false;
}
else
return true;
If either h_OurBitmap or hdc_OurBitmap does not load the bitmap correctly it will be equal to NULL. So what we're saying here is if h_OurBitmap equals NULL or (||) hdc_OurBitmap equals NULL, then display the message "Either your DC or HBITMAP, did not load correctly" and return false. If not then return true. That's it a real simple error checking routine.
Here is the whole function:
[CODE]
/*############################################################## #############################*/
bool LoadGraphics(HINSTANCE hInst)
{
//Init
the DC
hdc_OurBitmap
= CreateCompatibleDC(NULL);
//Load the bitmap into the HBITMAP and HDC
h_OurBitmap
= (HBITMAP)SelectObject(hdc_OurBitmap,LoadBitmap(hInst,MAKEINTRESOURCE(IDB_OURBITMAP))
);
//Insure that both loaded correctly
if((h_OurBitmap
== NULL) || (hdc_OurBitmap == NULL))
{
MessageBox(NULL,"Either your DC or HBITMAP, did not load correctly",NULL,NULL);
return false; //If they did not return
false
}
else
return true; //If they did return
true
}
[/CODE]
If you can get this, then you have ½ the battle done. Now comes actually BitBlt'ng it.
Well here is where a lot of things can go wrong. Now an equal amount of things can go wrong in the actual loading of the image, but at least there you can see you can see if the variables are equal to something. Here you really can't do much error checking but trial and error. Well then lets get to it
Before we get started I want to let you know that I made this function flexible. What I mean by that is that this function can be used to BitBlt to any DC, just by changing what gets passed in. I did not allow it to use any bitmap, but that's easy to change by simply adding another HDC pointer, that points to the DC of the bitmap you want to use.
So, lets look at the function:
bool DrawGraphics(HDC *hdc, int destX, int destY, int destWidth, int destHeight)
Lets see what is being passed in; well first up is a pointer to a HDC. The HDC that we are going to past in is the DC of what we want to BitBlt to. When we get to the main.cpp you will see what I mean. Next 2 ints, are the destination DC's, X and Y positions to start the overlay. Most of the time you will use 0, 0, here, but there might be times when you want the BitBlt to be offset for some reason. The final 2 ints, are the destination's Height and Width.
Normally you would put in the actually destination's height and width, but lets say that you only want to overlay part of a bitmap. Say for example, only a persons face from a bitmap that is of the entire person. Using the destination height and width, and the starting X and Y position on the bitmap (Don't worry we will get to that in a second) you can just transfer that part and not the whole bitmap. If you don't get it, try changing these after we have finished this program.
Now for the part you have all been waiting for, the actual BitBlt:
BitBlt(*hdc,destX,destY,destWidth,destHeight,hdc_OurBitmap,0,0,SRCCOPY);
Ok the first parameter is the HDC of the DC you want to BitBlt to. Since we passed in a pointer to the destination DC, we are going to use the * for pointer here. This parameter and the next four are using the variables passed in to the function.
As we already covered, the next two parameters are the destination DC's, X and Y positions, to start the BitBlt at. The next two parameters, destWidth, and destHeight, are of course the destination DC's width and height.
The next parameter, is the DC that you want to BitBlt from. In this case we want to use our bitmap. So we are going to use hdc_OurBitmap, which is of course, the HDC that is holding our bitmap. Ok the next two parameters, are the X and Y position to start BitBlt'ng from, on the DC we want to BitBlt from. Again most of the time you will probably use 0 and 0, which means start at position 0, 0, when starting the transfer.
Finally, the last parameter is what is called the raster operation code. For right now, lets just say that the raster operation code is how you want BitBlt to do it's job. There are a lot of options here, if you look up BitBlt in MSDN, or online, you will find all these options. For now we are just going to use SRCCOPY. SRCCOPY tell BitBlt to do an exact copy from one DC to the other and completely overlay the source DC, even if there is something all ready there.
Just so you have a better understanding of raster operation code, another one is SRCAND. What SRCAND does, is that BitBlt should copy from on DC to the other, but instead of an exact copy, it should combine the colors of both DCs together, using AND. What AND means is that say one color in an area, on the original DC, is yellow and on the same area on the BitBlt DC is blue. When it goes to BitBlt the two, it will add yellow and blue together on the final output. Yellow plus blue of course equals green. So that area will be green on the final output.
That is it for that function. It is that simple at this point. You might notice that we are returning a true without actually doing any error checking. Well we can't really at this point. Sure we could say return BitBlt(*hdc,destX,destY,destWidth,destHeight,hdc_OurBitmap,0,0,SRCCOPY); because BitBlt does return a true or false if the operation runs correctly. The problem is that you will only get a false if either of your DCs are wrong. That is about the only way a false will happen. In the Advanced BitBlt we will use it, but for now we will always return a ture.
Lets look at the whole Function :
[CODE]
/*############################################################## #############################*/
bool DrawGraphics(HDC *hdc, int destX, int
destY, int destWidth, int destHeight)
{
//Here
is where all of the hard work is put to work
BitBlt(*hdc,destX,destY,destWidth,destHeight,hdc_OurBitmap,0,0,SRCCOPY);
return true;
}
[/CODE]
Ok now lets clean up this mess:
This is our final function in bitbltgraphics.cpp. I am sure you can't wait for this to be done, but there is still some stuff we have to do in main.cpp. I know, I know, but this part is real simple.
Quick look at the function:
void CleanUp()
Nothing to it, we are not going to return anything, and we are not going to pass anything in. What we are going to do is help insure that the memory we allocated with our DC and HBITMAP are de-allocated correctly.
We are going to do this with two lines:
DeleteDC(hdc_OurBitmap);
DeleteObject(h_OurBitmap);
Really simple stuff right? We are just deleting a DC, in this case our bitmap's DC. We are also deleting our bitmap handle. Since that handle is an object, we use DeleteObject. That is it. Now for some quick changes to your main.cpp and we are done.
We will only be making one changes to the header file:
extern HWND m_hWnd_Main;
That is it. This variable will hold the hWnd to our static box. So with that, here is the code:
[CODE]
/********************************************************************** *****
Name: Main.h
Version: 1.3
Date Created: 2/20/2001
Discription:
Header file for Main.cpp
Main is the starting file for our program
Notes: None
Owner: Technocrat(technocrat@usa.com)
********************************************************************** *****/
#ifndef __MAIN_H__
#define __MAIN_H__